﻿#pragma once

#include <assert.h>

namespace dr
{
	template<class K, class V>
	struct AVLTreeNode
	{
		// 需要parent指针，后续更新平衡因⼦可以看到
		pair<K, V> _kv;
		AVLTreeNode<K, V>* _left;
		AVLTreeNode<K, V>* _right;
		AVLTreeNode<K, V>* _parent;
		int _bf; // balance factor
		AVLTreeNode(const pair<K, V>& kv)
			:_kv(kv)
			, _left(nullptr)
			, _right(nullptr)
			, _parent(nullptr)
			, _bf(0)
		{}
	};

	template<class K, class V>
	class AVLTree
	{
		typedef AVLTreeNode<K, V> Node;
	public:
		//...
		bool insert(const pair<K, V>& kv)
		{
			if (_root == nullptr)
			{
				_root = new Node(kv);
			}
			else
			{
				Node* cur = _root;
				Node* parent = nullptr;
				while (cur)
				{
					if (kv.first < cur->_kv.first)
					{
						parent = cur;
						cur = cur->_left;
					}
					else if (kv.first > cur->_kv.first)
					{
						parent = cur;
						cur = cur->_right;
					}
					else
					{
						return false;
					}
				}

				if (kv < parent->_kv.first)
				{
					parent->_left = new Node(kv);
				}
				else
				{
					parent->_right = new Node(kv);
				}
				cur->_parent = parent;

				// 更新平衡因子
				while (parent)
				{
					if (cur == parent->_left)
					{
						parent->_bf--;
					}
					else if (cur == parent->_right)
					{
						parent->_bf++;
					}

					if (parent->_bf == 0)
					{
						break;
					}
					else if (parent->_bf == -1 || parent->_bf == 1)
					{
						cur = parent;
						parent = cur->_parent;
					}
					else if (parent->_bf == -2 || parent->_bf == 2)
					{
						if (parent->_bf == -2 && cur->_bf == -1)
						{
							// 右单旋
							RotateR(parent);
						}
						else if (parent->_bf == -2 && cur->_bf == -1)
						{
							// 左单旋
							RotateL(parent);
						}
						break;
					}
					else
					{
						return assert(false);
					}

				}
			}
			return true;
		}

	private:
		void RotateR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;

			Node* ppNode = parent->_parent;

			parent->_left = subRL;
			if (subLR)
				subLR->_parent = parent;
			subL->_right = parent;
			parent->_parent = subL;

			if (ppNode == nullptr)
			{
				_root = parent;
			}
			else
			{
				if (ppNode->_left == parent)
				{
					ppNode->_left = subL;
				}
				else
				{
					ppNode->_right = subL;
				}
			}

			parent->_bf = subL->_bf = 0;
		}

		void RotateL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;

			Node* ppNode = parent->_parent;

			parent->_right = subRL;
			if (subRL)
				subRL->_parent = parent;
			subR->_left = parent;
			parent->_parent = subR;

			if (ppNode == nullptr)
			{
				_root = parent;
			}
			else
			{
				if (ppNode->_left == parent)
				{
					ppNode->_left = subR;
				}
				else
				{
					ppNode->_right = subR;
				}
			}

			subR->_bf = parent->_bf = 0;
		}

	private:
		Node* _root;
	};
}